﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;

namespace Komunikator.Core
{
    /* writer do socketa, zeby latwiej bylo wysylac pakiet protokolu gg
     */
    class SocketStreamWriter
    {

        private Socket socket;
        private NetworkStream netStream;

        public SocketStreamWriter(Socket sock)
        {

            socket = sock;
            netStream = new NetworkStream(socket);
            netStream.WriteTimeout = 100;

        }

        public SocketStreamWriter(NetworkStream stream)
        {
            netStream = stream;
            //netStream.WriteTimeout = 100;
        }

        public void WriteGGpacket(GGheader header)
        {
            byte[] buff = RawSerialize(header);
            netStream.Write(buff, 0, buff.Length);
        }

        public void WriteGGpacket(GGlogin80 loginPacket)
        {
            byte[] buff = RawSerialize(loginPacket);
            netStream.Write(buff, 0, buff.Length);
        }

        

        public void ChangeStatus(string status) //TODO: to delete - old
        {
            GGheader header = new GGheader();
            GGnewStatus80 newStat = new GGnewStatus80();
            List<byte> bytesArray = new List<byte>();

            header.type = Packets.GG_NEW_STATUS80;

            newStat.flags = GGlogin800.flags;
            newStat.description_size = 0;
            switch (status)
            {
                case "Dostępny": newStat.status = Packets.GG_STATUS_AVAIL; break;
                default: newStat.status = Packets.GG_STATUS_DND; break;

            }

            newStat.status = Packets.GG_STATUS_AVAIL;
            newStat.flags =  0x00000003;

            bytesArray.AddRange(BitConverter.GetBytes(newStat.status));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.flags));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.description_size));

            header.length = bytesArray.Count;

            byte[] connectedBytes = new byte[8 + bytesArray.Count];
            byte[] headerBytes = RawSerialize(header);
            byte[] messageBytes = bytesArray.ToArray();

            Buffer.BlockCopy(headerBytes, 0, connectedBytes, 0, headerBytes.Length);
            Buffer.BlockCopy(messageBytes, 0, connectedBytes, headerBytes.Length, messageBytes.Length);

            //WriteGGpacket(header);
            //Thread.Sleep(2);
            //WriteGGpacket(bytesArray);
            //Thread.Sleep(2);

            //Thread.Sleep(2);
            netStream.Flush();
            WriteGGpacket(connectedBytes);
            netStream.Flush();
            //Thread.Sleep(2);


        }

        public void ChangeStatus(int ggStatusCode)
        {
            GGheader header = new GGheader();
            GGnewStatus80 newStat = new GGnewStatus80();
            List<byte> bytesArray = new List<byte>();

            header.type = Packets.GG_NEW_STATUS80;

            newStat.flags = GGlogin800.flags;
            newStat.description_size = 0;
            newStat.status = ggStatusCode;
            newStat.flags = 0x00000003;

            bytesArray.AddRange(BitConverter.GetBytes(newStat.status));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.flags));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.description_size));

            header.length = bytesArray.Count;

            byte[] connectedBytes = new byte[8 + bytesArray.Count];
            byte[] headerBytes = RawSerialize(header);
            byte[] messageBytes = bytesArray.ToArray();

            Buffer.BlockCopy(headerBytes, 0, connectedBytes, 0, headerBytes.Length);
            Buffer.BlockCopy(messageBytes, 0, connectedBytes, headerBytes.Length, messageBytes.Length);

            netStream.Flush();
            WriteGGpacket(connectedBytes);
        }

        public void ChangeStatus(int ggStatusCode, string desc)
        {
            GGheader header = new GGheader();
            GGnewStatus80 newStat = new GGnewStatus80();
            List<byte> bytesArray = new List<byte>();

            header.type = Packets.GG_NEW_STATUS80;

            newStat.flags = GGlogin800.flags;
            newStat.description_size = 0;
            newStat.status = ggStatusCode;
            newStat.flags = GGlogin800.flags;
            newStat.description = UTF8Encoding.UTF8.GetBytes(desc);
            newStat.description_size = newStat.description.Length;

            bytesArray.AddRange(BitConverter.GetBytes(newStat.status));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.flags));
            bytesArray.AddRange(BitConverter.GetBytes(newStat.description_size));

            header.length = bytesArray.Count;

            byte[] connectedBytes = new byte[8 + bytesArray.Count];
            byte[] headerBytes = RawSerialize(header);
            byte[] messageBytes = bytesArray.ToArray();

            Buffer.BlockCopy(headerBytes, 0, connectedBytes, 0, headerBytes.Length);
            Buffer.BlockCopy(messageBytes, 0, connectedBytes, headerBytes.Length, messageBytes.Length);

            netStream.Flush();
            WriteGGpacket(connectedBytes);
        }

        public void WriteGGpacket(List<byte> ggBytesList)
        {
            byte[] buff = ggBytesList.ToArray();
            netStream.Write(buff, 0, buff.Length);
        }

        public void WriteEmptyListNotify()
        {
            GGheader header = new GGheader();
            header.type = 0x0012;
            header.length = 0;
            byte[] buff = RawSerialize(header);
            netStream.Write(buff, 0, buff.Length);
        }

        public void WriteGGpacket(byte[] ggBytes)
        {
            netStream.Write(ggBytes, 0, ggBytes.Length);
        }

        public static byte[] RawSerialize(object anything) //zamiana struct w bytes[] zeby przeslac przez siec
        {
            int rawsize = Marshal.SizeOf(anything);
            IntPtr buffer = Marshal.AllocHGlobal(rawsize);
            Marshal.StructureToPtr(anything, buffer, false);
            byte[] rawdatas = new byte[rawsize];
            Marshal.Copy(buffer, rawdatas, 0, rawsize);
            Marshal.FreeHGlobal(buffer);
            return rawdatas;
        } 

    }
}
